#!/usr/bin/python
# coding:utf-8

# from flask_security.decorators import roles_accepted, auth_token_required
import requests
import random
import string
import time
from flask import current_app
from flask_restful import Resource, reqparse
from flask_security import login_user, auth_token_required, roles_accepted
from sqlalchemy import and_
from sqlalchemy.sql import func

from src.models.auth import AuthInstance, SocialAccount
from src.models.user import User
from src.utils.api import OpenResource
from src.utils.models import db
from src.utils.send_mail import send_mail
from src.utils.serializing import Serializer
from src.utils.ErrorMsg import Message

__author__ = 'Methew Pan'
__create__time = '20180429'

'''
oauth2 step
step 1 send window name
|
->step 2.1 Send auth email code|| step 2.2 Social Login
              |                             |
                  |                     |
                     |               |
                         |       |
                        step3 UserCheck
'''


# oath2 login step
# step1 Send windows name
# wd = open()
# wd.id = provider+windowName
class SendWindowName(OpenResource):
    parser = reqparse.RequestParser() \
        .add_argument('windowName', type=str, location=['json', 'form']) \
        .add_argument('provider', type=str, location=['json', 'form'])

    def __init__(self):
        self.windowName = Serializer(current_app).serialize_data(
            {
                'string': ''.join(random.sample(string.ascii_letters + string.digits, 15)),
                'id': time.time() * 1000
            })

    def insertItem(self, args):
        try:
            print(self.windowName)
            if args['provider'] is not None:
                auth = AuthInstance(
                    window_name=self.windowName, provider=args['provider'])
            else:
                auth = AuthInstance(window_name=self.windowName)
            auth.arg()
            db.session.add(auth)
            db.session.commit()
            return {"error_code": 0, "message": "完成数据提交",
                    "data": {"window_name": self.windowName, "provider": args['provider']}}, 200
        except ValueError:
            return Message('DataBaseTypeError').Msg()

    def updateItem(self, args, ai):
        try:
            if args['provider'] is not None:
                ai.provider = args['provider']
                db.session.commit()
                return {"error_code": 0, "message": "已经提交不用重复提交",
                        "data": {"window_name": args['windowName'], "provider": args['provider']}}, 200
            else:
                return {"error_code": 0, "message": "已经提交不用重复提交",
                        "data": {"window_name": args['windowName'], "provider": args['provider']}}, 200
        except ValueError:
            return Message('DataBaseTypeError').Msg()

    def post(self):
        args = self.parser.parse_args()
        print(args)
        # wn = args['windowName']
        # pd = args['provider']
        # 创建windowName
        if args['windowName'] is None or args['windowName'] == 'undefined' or args['windowName'] == '':
            print('windowsname is none or window')
            return self.insertItem(args)
        else:
            ai = db.session.query(AuthInstance) \
                .filter(AuthInstance.window_name == args['windowName']) \
                .filter(AuthInstance.is_logout == 1) \
                .first()
            print(ai)
            if ai and Serializer(current_app).deserialize_data(ai.window_name) is not None:
                print('windowname is ' + ai.window_name)
                return self.updateItem(args, ai)
            else:
                return self.insertItem(args)


# step2.1 Send auth email code
class SendVerificationEmail(OpenResource):
    parser = reqparse.RequestParser() \
        .add_argument('windowName', type=str, location=['json', 'form'], required=True, help="全局内码不能为空") \
        .add_argument('email', type=str, location=['json', 'form'], required=True, help="电邮地址不能为空")

    def get(self):
        return 'SendAuthEmail'

    def post(self):
        args = self.parser.parse_args()
        print(args)
        # 查询用户
        user = User.query.filter_by(email=args['email']).first()
        print('user is ', user)
        if user:
            code, token = user.get_auth_code()
            try:
                ai = db.session.query(AuthInstance) \
                    .filter(AuthInstance.window_name == args['windowName']).first()
                ai.code = code
                ai.provider = 'email'
                ai.access_token = token
                ai.expires = current_app.config['SECURITY_TOKEN_MAX_AGE']
                ai.provider_id = args['email']
                ai.email = args['email']
                ai.expires_time = func.now()

                db.session.commit()
            except:
                return {"error_code": 20001, "message": "数据库提交错误"}, 401
            html = ("欢迎邮箱为{email}的用户！<br/>请确认此邮件地址以登录您的账号。<br/>"
                    "<font color='red'><a href='{confirmation_link}'target='_blank'>立即登录</a></font><br/>"
                    "或者点击下面链接:<br/>{confirmation_link}<br/>"
                    "这是一封自动发送的邮件；"
                    "如果您并未要求但收到这封信件，"
                    "您不需要进行任何操作。") \
                .format(email=args['email'],
                        confirmation_link="http://localhost:3000/login?code={code}".format(code=code))
            send_mail(sender=current_app.config['MAIL_USERNAME'], recipients=args['email'],
                      subject='欢迎登录melog账号,请点击登录账号', html=html)
            return {"error_code": 0, "message": "登录信息已经发到登记邮箱", "data": {"isUser": 1, "user": user}}, 200
        else:
            log_msg = '用户没有，要注册'
            s = Serializer(current_app)
            token = s.serialize_data([args['email']])
            code = s.get_code()
            try:
                ai = db.session.query(AuthInstance) \
                    .filter(AuthInstance.window_name == args['windowName']).first()
                ai.provider = 'email'
                ai.code = code
                ai.access_token = token
                ai.expires = current_app.config['SECURITY_TOKEN_MAX_AGE']
                ai.provider_id = args['email']
                ai.email = args['email']
                ai.expires_time = func.now()

                db.session.commit()
            except:
                return {"error_code": 20001, "message": "数据库提交错误"}, 401

            html = "欢迎邮箱为{email}的用户！<br/>请确认此邮件地址以激活您的账号。<br/>" \
                   "<font color='red'><a href='{confirmation_link}'target='_blank'>立即激活</a></font><br/>" \
                   "或者点击下面链接:<br/>{confirmation_link}<br/>" \
                   "这是一封自动发送的邮件；" \
                   "如果您并未要求但收到这封信件，" \
                   "您不需要进行任何操作。" \
                .format(email=args['email'],
                        confirmation_link="http://localhost:3000/regist?code={code}".format(code=code))
            send_mail(sender=current_app.config['MAIL_USERNAME'], recipients=args['email'],
                      subject='欢迎注册melog账号,请点击链接激活账号', html=html)
            return {"error_code": 0, "message": "注册信息已经发到填报邮箱", "data": {"isUser": 0}}, 200


class GetAuthUrl(OpenResource):
    def post(self, provider, redirect_uri):
        from urllib import parse
        if provider == 'google':
            return Message().Msg(None, 'google provider', data={
                'auth': current_app.config['SOCIAL_CONFIG'][provider]['oauth']['auth'],
                'qs': {
                    'client_id': current_app.config['SOCIAL_CONFIG'][provider]['id'],
                    'response_type': current_app.config['SOCIAL_CONFIG'][provider]['oauth']['response_type'],
                    'scope': [current_app.config['SOCIAL_CONFIG'][provider]['oauth']['scope']['email']],
                    'redirect_uri': redirect_uri,
                    'access_type': 'offline'
                }
            })
        else:
            return Message().Msg(None, '其它provider', data={
                'auth': current_app.config['SOCIAL_CONFIG'][provider]['oauth']['auth'],
                'qs': {
                    'client_id': current_app.config['SOCIAL_CONFIG'][provider]['id'],
                    'response_type': current_app.config['SOCIAL_CONFIG'][provider]['oauth']['response_type'],
                    'scope': [current_app.config['SOCIAL_CONFIG'][provider]['oauth']['scope']['email']],
                    'redirect_uri': redirect_uri
                }
            })


# step2.2 Social Send code
class SendCode(OpenResource):
    parser = reqparse.RequestParser() \
        .add_argument("windowName", type=str, location=['form', 'json'], required=True, help="窗口编码不能为空") \
        .add_argument("code", type=str, location=['form', 'json'], required=True, help="code不能为空")

    def post(self):
        args = self.parser.parse_args()
        print(args)
        # 获取授权实例基本信息
        try:
            ai = db.session.query(AuthInstance).filter(
                AuthInstance.window_name == args['windowName']).first()
            print(ai.window_name)
            ai.code = args['code']
            db.session.commit()
            return Message().Msg(None, "添加上code", data={"windowName": ai.window_name, "code": ai.code})
        except:
            return Message().Msg('RequestTypeError')


# step2.2 Social Login
class VerifySocial(OpenResource):
    parser = reqparse.RequestParser() \
        .add_argument("windowName", type=str, location=['form', 'json'], required=True, help="窗口编码不能为空") \
        .add_argument("redirectUri", type=str, location=['form', 'json'], required=True, help="不能为空")

    def __init__(self):
        self.SocailConfigs = current_app.config['SOCIAL_CONFIG']

    def getAcessToken(self, provider, ai, redirectUri):
        headers = {
            'Accept': 'application/json',
            'content-type': 'application/x-www-form-urlencoded'
        }
        payload = {
            'client_id': self.SocailConfigs[provider]['id'],
            'client_secret': self.SocailConfigs[provider]['secret'],
            'grant_type': 'authorization_code',
            'code': ai.code,
            'redirect_uri': redirectUri
        }
        # 获取授权服务器回传授权数据 access_token
        print(self.SocailConfigs[provider]['grand'])
        if self.SocailConfigs[provider]['grandMethod'] == 'get':
            r = requests.get(
                self.SocailConfigs[provider]['grand'], params=payload, headers=headers).json()
        elif self.SocailConfigs[provider]['grandMethod'] == 'post-params':
            r = requests.post(
                self.SocailConfigs[provider]['grand'], params=payload, headers=headers).json()
        elif self.SocailConfigs[provider]['grandMethod'] == 'post-form':
            r = requests.post(
                self.SocailConfigs[provider]['grand'], data=payload, headers=headers).json()
        else:
            return {"message": '无法判断grand获取方法'}, 401
            # 对获取信息r 分辨具体内容
        print(r)
        if 'error' in r:
            print(r.get('error_description'))
            return {"message": r.get('error_description')}, 401
        if 'expires_in' in r:
            ai.oauth_expires = r.get('expires_in')
        else:
            ai.oauth_expires = current_app.config['SECURITY_TOKEN_MAX_AGE']
        if 'access_token' in r:
            ai.oauth_access_token = r.get('access_token')
        else:
            return {"message": '返回值无法识别'}, 401
        # if provider == 'weibo' and 'uid' in r:
        #     ai.provider_id = r.get('uid')
        #     user = db.session.query(User). \
        #         filter(
        #         and_(User.sns_id == args['uid'], User.sns_type == args['type'])).first()
        #     if user:
        #         login_user(user=user)
        #         return Message().Msg(None, "登录成功", data={"user": {"email": user.email}})
        #     else:
        #         return {"message": "用户不存在"}, 401
        # if provider == 'google':
        #     url = self.SocailConfigs[provider]['base'] + \
        #           self.SocailConfigs[provider]['api']['me']
        #     rge = requests.get(
        #         url, params={'access_token': r.get('access_token')})
        #     print(rge.text)
        try:
            db.session.commit()
            return {"provider": ai.provider, "windowName": ai.window_name, 'access_token': ai.access_token}
        except:
            return {"message": '无法判断grand获取方法'}, 401

    def getMe(self, access_token):
        me, type = self.SocailConfigs[provider]['api']['me']
        url = self.SocailConfigs[provider]['base'] + me
        print(type(ret))
        if type == 'get' and type(ret) == 'dict':
            print(ret)
            meRet = requests.get(
                url, params={'access_token': ret['access_token']})
        if meRet.status_code == 200 and provider == 'google':
            user = {"id": meRet.id, "email": meRet["emails"]["value"], "displayName": meRet["displayName"],
                    "thumbnail": meRet['image']['url']}
            return Message().Msg(None, '获得', data=user)

    def post(self, provider):
        args = self.parser.parse_args()
        # 获取授权实例基本信息
        ai = db.session.query(AuthInstance).filter(AuthInstance.window_name == args['windowName']) \
            .filter(AuthInstance.provider == provider).first()
        if ai is None:
            return Message().Msg(errortype='DataNoIncludeDataError')
        ret = self.getAcessToken(provider, ai, args['redirectUri'])
        getMe(ret.access_token)


# step3 get user information
class CheckUser(OpenResource):
    parser = reqparse.RequestParser() \
        .add_argument('windowName', type=str, location='json', required=True, help="windowName is not null") \
        .add_argument('provider', type=str, location='json', required=True, help="provider is not null") \
        .add_argument('provider_id', type=str, location='json', required=True, help="provider_id is not null") \
        .add_argument('code', type=str, location='json', required=True, help="code is not null")

    def post(self):
        args = self.parser.parse_args()
        if args['type'] == 'email':
            # 如果是email登录
            # step 1:查询code是不是在授权实例表（AuthInstance）内,provider_id在这代表这email
            # TODO:
            ai = db.session.query(AuthInstance).filter(
                and_(AuthInstance.window_name == args['windowName'], AuthInstance.code == args['code'],
                     AuthInstance.provider == 'email')).first()
            user = db.session.query(User). \
                filter(and_(User.email == args['provider_id'])).first()

            if user:
                if user.verify_auth_token(ai.access_token) is not None:
                    login_user(user=user)
                    return {"error_code": 0, "message": "user", "user": user.get_setup()}, 201
                else:
                    return {'error_code': 10001, "message": "user auth error"}, 401
            else:
                return {"error_code": 10500, "message": "用户不存在", "user": None}, 401
        else:
            # 如果不是email登录则要判断是否在社交媒体账户内
            sc = db.session.query(SocialAccount).filter(and_(
                SocialAccount.social_id == args['name'], SocialAccount.provider == args['provider'])).first()

            if sc:
                # 如果社交媒体账户含有则可以查询具体的人员信息
                user = db.session.query(User).filter(
                    User.id == sc.user_id).first()
                return {"error_code": 0, "message": "user", "user": user.get_setup()}, 201
            else:
                return {"error_code": 10500, "message": "用户不存在", "user": None}, 401


class Test(OpenResource):
    parser = reqparse.RequestParser()

    def get(self):
        return '11'

    def post(self):
        self.parser.add_argument('id', type=str, location=['form', 'json'])
        args = self.parser.parse_args()
        print(args)
        return 'test'


class Regist(Resource):
    @roles_accepted('admin')
    def post(self):
        args = reqparse.RequestParser() \
            .add_argument('username', type=str, location='json', required=True, help="用户名不能为空") \
            .add_argument("reigistType", type=str, location='json', required=True, help="密码不能为空") \
            .parse_args()
